/**********************************************************************
* Filename: Membro.java
* Created: 2012/04/30
* @author Fernando Brito e Abreu
**********************************************************************/
package pt.iscteiul.worldfootball.businesslayer;

import java.util.Set;
import java.util.HashSet;

import com.projectpoint.annotationnotfinished.NotFinished;
@NotFinished(value="Not tested")
public class Membro implements Cloneable
{
	public static Set<Membro> allInstances = new HashSet<Membro>();
	
	private int minuto_entrada;
	private int minuto_saida;
	private Equipa equipa;
	private Jogador jogador;
	
	private Membro OLD;
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		Membro membro = new Membro(minuto_entrada,minuto_saida,(Equipa)equipa.clone(), (Jogador)jogador.clone());
		Membro.allInstances.remove(membro);
		return membro;
	}
	protected boolean _Invariant(){
		//let origem_seleccao = equipa.seleccao in jogador.nacionalidade=origem_seleccao
		Pais origem_seleccao = equipa().seleccao();
		boolean jogadorDaEquipaTemNacionalidadeCorrecta = jogador.nacionalidade().equals(origem_seleccao);
		return jogadorDaEquipaTemNacionalidadeCorrecta;
	}
	
	/**********************************************************************
	* Default constructor
	**********************************************************************/
	public Membro()
	{
		allInstances.add(this);
	}
	
	/**********************************************************************
	* Parameterized constructor
	* @param minuto_entrada the minuto_entrada to initialize
	* @param minuto_saida the minuto_saida to initialize
	* @param equipa the equipa to initialize
	* @param jogador the jogador to initialize
	**********************************************************************/
	public Membro(int minuto_entrada, int minuto_saida, Equipa equipa, Jogador jogador)
	{
		this.minuto_entrada = minuto_entrada;
		this.minuto_saida = minuto_saida;
		this.equipa = equipa;
		this.jogador = jogador;
		allInstances.add(this);
	}
	
	/**********************************************************************
	* Standard attribute getter
	* @return the minuto_entrada of the membro
	**********************************************************************/
	public int minuto_entrada()
	{
		return minuto_entrada;
	}
	
	/**********************************************************************
	* Standard attribute setter
	* @param minuto_entrada the minuto_entrada to set
	**********************************************************************/
	public void setMinuto_entrada(int minuto_entrada)
	{
		this.minuto_entrada = minuto_entrada;
	}
	
	/**********************************************************************
	* Standard attribute getter
	* @return the minuto_saida of the membro
	**********************************************************************/
	public int minuto_saida()
	{
		return minuto_saida;
	}
	
	/**********************************************************************
	* Standard attribute setter
	* @param minuto_saida the minuto_saida to set
	**********************************************************************/
	public void setMinuto_saida(int minuto_saida)
	{
		this.minuto_saida = minuto_saida;
	}
	
	/**********************************************************************
	* ASSOCIATIVE2MEMBER getter for Membro[*] <-> Equipa[1]
	* @return the equipa of the membro
	**********************************************************************/
	public Equipa equipa()
	{
		return equipa;
	}
	
	/**********************************************************************
	* ASSOCIATIVE2MEMBER setter for Membro[*] <-> Equipa[1]
	* @param equipa the equipa to set
	**********************************************************************/
	public void setEquipa(Equipa equipa)
	{
		this.equipa = equipa;
	}
	
	/**********************************************************************
	* ASSOCIATIVE2MEMBER getter for Membro[*] <-> Jogador[1]
	* @return the jogador of the membro
	**********************************************************************/
	public Jogador jogador()
	{
		return jogador;
	}
	
	/**********************************************************************
	* ASSOCIATIVE2MEMBER setter for Membro[*] <-> Jogador[1]
	* @param jogador the jogador to set
	**********************************************************************/
	public void setJogador(Jogador jogador)
	{
		this.jogador = jogador;
	}
	
	/**********************************************************************
	* ONE2MANY getter for Membro[1] <-> Cartao[0..2]
	* @return the cartoes of the membro
	**********************************************************************/
	public Set<Cartao> cartoes()
	{
		Set<Cartao> result = new HashSet<Cartao>();
		for (Cartao x : Cartao.allInstances)
			if (x.membro()  ==  this)
				result.add(x);
		return result;
	}
	
	/**********************************************************************
	* ONE2MANY setter for Membro[1] <-> Cartao[0..2]
	* @param cartoes the cartoes to set
	**********************************************************************/
	public void setCartoes(Set<Cartao> cartoes)
	{
		for (Cartao x : cartoes)
			x.setMembro(this);
	}
	
	/**********************************************************************
	* ONE2MANY getter for Membro[1] <-> Golo[*]
	* @return the golos of the marcador
	**********************************************************************/
	public Set<Golo> golos()
	{
		Set<Golo> result = new HashSet<Golo>();
		for (Golo x : Golo.allInstances)
			if (x.marcador()  ==  this)
				result.add(x);
		return result;
	}
	
	/**********************************************************************
	* ONE2MANY setter for Membro[1] <-> Golo[*]
	* @param golos the golos to set
	**********************************************************************/
	public void setGolos(Set<Golo> golos)
	{
		for (Golo x : golos)
			x.setMarcador(this);
	}
	
	/**********************************************************************
	* User-defined operation specified in SOIL/OCL
	* @param cartoes the cartoes to set
	**********************************************************************/
	public void inserirCartoes(Set<Cartao> cartoes)
	{
		//	TODO
		//	for cartao in cartoes do insert (self,cartao) into Membro_Cartao end;
		for(Cartao cartao:this.cartoes()){
			cartao.setMembro(this);
		}
		this.setCartoes(cartoes);
	}
	
	protected boolean inserirCartoes_Precondition(Set<Cartao> cartoes){
		//self.cartoes.tipo->count(#Amarelo)+cartoes.tipo->select(t|t=#Amarelo)->size<=2
		boolean podeDarCartoesAmarelos1 = true;
		int amarelos = 0;
		for(Cartao c:this.cartoes()){
			if(c.tipo().equals(TipoCartao.Amarelo)){
				amarelos++;
			}
		}
		for(Cartao c:cartoes){
			if(c.tipo().equals(TipoCartao.Amarelo)){
				amarelos++;
			}
		}
		if(amarelos>=3){
			podeDarCartoesAmarelos1 = false;
		}
		
		//cartoes.tipo->exists(t|t=#Amarelo) implies not self.cartoes.tipo->exists(t|t=#Vermelho)
		boolean podeDarCartoesAmarelos2 = true;
		boolean exists = false;
		for(Cartao c:cartoes){
			if(c.tipo().equals(TipoCartao.Amarelo)){
				exists = true;
			}
		}
		if(exists){
			for(Cartao c:this.cartoes()){
				if(c.tipo().equals(TipoCartao.Vermelho)){
					podeDarCartoesAmarelos2 = false;
					break;
				}
			}
		}
		//self.cartoes.tipo->count(#Vermelho)+cartoes.tipo->select(t|t=#Vermelho)->size<=1
		boolean podeDarCartoesVermelhos1 = true;
		int vermelhos = 0;
		for(Cartao c:this.cartoes()){
			if(c.tipo().equals(TipoCartao.Vermelho)){
				vermelhos++;
			}
		}
		for(Cartao c:cartoes){
			if(c.tipo().equals(TipoCartao.Vermelho)){
				vermelhos++;
			}
		}
		if(vermelhos>1){
			podeDarCartoesVermelhos1 = false;
		}
		//cartoes.tipo->exists(t|t=#Vermelho) implies self.cartoes.tipo->count(#Amarelo)<2
		boolean podeDarCartoesVermelhos2 = true;
		exists = false;
		for(Cartao c:cartoes){
			if(c.tipo().equals(TipoCartao.Vermelho)){
				exists =true;
				break;
			}
		}
		if(exists){
			amarelos=0;
			for(Cartao c:this.cartoes()){
				if(c.tipo().equals(TipoCartao.Amarelo)){
					amarelos++;
				}
			}
			if(amarelos>2){
				podeDarCartoesVermelhos2 = false;
			}
		}
		return podeDarCartoesAmarelos1 && podeDarCartoesAmarelos2 && podeDarCartoesVermelhos1 && podeDarCartoesVermelhos2;
	}
	
	protected boolean inserirCartoes_Postcondition(Set<Cartao> cartoes, Void RETURN){
		//self.cartoes.tipo->count(#Amarelo) = self.cartoes@pre.tipo->count(#Amarelo)+cartoes.tipo->count(#Amarelo)
		boolean cartoesAmarelosDados = true;
		int amarelos = 0;
		for(Cartao c:this.cartoes()){
			if(c.tipo().equals(TipoCartao.Amarelo)){
				amarelos++;
			}
		}
		int amarelosOldCount = 0;
		for(Cartao c:OLD.cartoes()){
			if(c.tipo().equals(TipoCartao.Vermelho)){
				amarelosOldCount++;
			}
		}
		if(amarelos!=amarelosOldCount){
			cartoesAmarelosDados = false;
		}
		//self.cartoes.tipo->count(#Vermelho) = self.cartoes@pre.tipo->count(#Vermelho)+cartoes.tipo->count(#Vermelho)
		boolean cartoesVermelhosDados = true;
		int vermelhos = 0;
		for(Cartao c:this.cartoes()){
			if(c.tipo().equals(TipoCartao.Vermelho)){
				vermelhos++;
			}
		}
		int vermelhosOldCount = 0;
		for(Cartao c:OLD.cartoes()){
			if(c.tipo().equals(TipoCartao.Vermelho)){
				vermelhosOldCount++;
			}
		}
		if(vermelhos!=vermelhosOldCount){
			cartoesVermelhosDados = false;
		}
		return cartoesAmarelosDados && cartoesVermelhosDados;
	}
	
	/* (non-Javadoc)
	* @see java.lang.Object#toString()
	*/
	@Override
	/**********************************************************************
	* Object serializer
	**********************************************************************/
	public String toString()
	{
		return "Membro [minuto_entrada=" + minuto_entrada + ", minuto_saida=" + minuto_saida + ", equipa=" + equipa + ", jogador=" + jogador + "]\n";
	}
	
}
